<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Forking 工作流 | 我的笔记</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link rel="icon" href="/notebook/favicon.ico">
    <script data-ad-client="ca-pub-4147143076931995" async="true" src="/notebook//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
    <meta name="description" content="方便阅读和寻找">
    
    <link rel="preload" href="/notebook/assets/css/0.styles.cee65b40.css" as="style"><link rel="preload" href="/notebook/assets/js/app.400f01da.js" as="script"><link rel="preload" href="/notebook/assets/js/2.ffba27f2.js" as="script"><link rel="preload" href="/notebook/assets/js/12.125d7a59.js" as="script"><link rel="prefetch" href="/notebook/assets/js/10.9da57264.js"><link rel="prefetch" href="/notebook/assets/js/100.8aa79850.js"><link rel="prefetch" href="/notebook/assets/js/101.f8819976.js"><link rel="prefetch" href="/notebook/assets/js/102.7168e4aa.js"><link rel="prefetch" href="/notebook/assets/js/103.e1f049f7.js"><link rel="prefetch" href="/notebook/assets/js/104.0ada8567.js"><link rel="prefetch" href="/notebook/assets/js/105.77e95b95.js"><link rel="prefetch" href="/notebook/assets/js/106.9071202a.js"><link rel="prefetch" href="/notebook/assets/js/107.a0a63241.js"><link rel="prefetch" href="/notebook/assets/js/108.93ccf0bf.js"><link rel="prefetch" href="/notebook/assets/js/109.57caff98.js"><link rel="prefetch" href="/notebook/assets/js/11.d9d769c3.js"><link rel="prefetch" href="/notebook/assets/js/110.6aa16c3f.js"><link rel="prefetch" href="/notebook/assets/js/111.293e18e5.js"><link rel="prefetch" href="/notebook/assets/js/112.7f593e53.js"><link rel="prefetch" href="/notebook/assets/js/113.e03d7fe0.js"><link rel="prefetch" href="/notebook/assets/js/114.4fd73421.js"><link rel="prefetch" href="/notebook/assets/js/115.8dc5910d.js"><link rel="prefetch" href="/notebook/assets/js/116.fc5215b7.js"><link rel="prefetch" href="/notebook/assets/js/117.851bae37.js"><link rel="prefetch" href="/notebook/assets/js/118.03cb2186.js"><link rel="prefetch" href="/notebook/assets/js/119.17f93b7e.js"><link rel="prefetch" href="/notebook/assets/js/120.4ea767fb.js"><link rel="prefetch" href="/notebook/assets/js/121.483ad579.js"><link rel="prefetch" href="/notebook/assets/js/122.17d2596f.js"><link rel="prefetch" href="/notebook/assets/js/123.56e20e4e.js"><link rel="prefetch" href="/notebook/assets/js/124.2ec822f9.js"><link rel="prefetch" href="/notebook/assets/js/125.bccb84ed.js"><link rel="prefetch" href="/notebook/assets/js/126.e38a7466.js"><link rel="prefetch" href="/notebook/assets/js/127.43962ebd.js"><link rel="prefetch" href="/notebook/assets/js/128.23f8246b.js"><link rel="prefetch" href="/notebook/assets/js/129.e718e26c.js"><link rel="prefetch" href="/notebook/assets/js/13.f56b83ad.js"><link rel="prefetch" href="/notebook/assets/js/130.a51fe94d.js"><link rel="prefetch" href="/notebook/assets/js/131.64fb54a3.js"><link rel="prefetch" href="/notebook/assets/js/132.badc2a1a.js"><link rel="prefetch" href="/notebook/assets/js/133.72f12c19.js"><link rel="prefetch" href="/notebook/assets/js/134.0b1b2dc0.js"><link rel="prefetch" href="/notebook/assets/js/135.be2d740c.js"><link rel="prefetch" href="/notebook/assets/js/136.c3dc9ba1.js"><link rel="prefetch" href="/notebook/assets/js/137.784510e4.js"><link rel="prefetch" href="/notebook/assets/js/138.ff844e48.js"><link rel="prefetch" href="/notebook/assets/js/139.1ac43f97.js"><link rel="prefetch" href="/notebook/assets/js/14.3ed225c4.js"><link rel="prefetch" href="/notebook/assets/js/140.4c427bf3.js"><link rel="prefetch" href="/notebook/assets/js/141.459f2cb4.js"><link rel="prefetch" href="/notebook/assets/js/142.e69e2b00.js"><link rel="prefetch" href="/notebook/assets/js/143.b9cd433a.js"><link rel="prefetch" href="/notebook/assets/js/144.c12cb09a.js"><link rel="prefetch" href="/notebook/assets/js/145.43e25cc4.js"><link rel="prefetch" href="/notebook/assets/js/146.0963c075.js"><link rel="prefetch" href="/notebook/assets/js/147.37f2e690.js"><link rel="prefetch" href="/notebook/assets/js/148.631fbe69.js"><link rel="prefetch" href="/notebook/assets/js/149.a22c5490.js"><link rel="prefetch" href="/notebook/assets/js/15.10a06d24.js"><link rel="prefetch" href="/notebook/assets/js/150.e6265d54.js"><link rel="prefetch" href="/notebook/assets/js/151.aefdb9fd.js"><link rel="prefetch" href="/notebook/assets/js/152.a8c722bd.js"><link rel="prefetch" href="/notebook/assets/js/153.ec2b1513.js"><link rel="prefetch" href="/notebook/assets/js/154.4fdc765f.js"><link rel="prefetch" href="/notebook/assets/js/155.de537bd1.js"><link rel="prefetch" href="/notebook/assets/js/156.7f87247c.js"><link rel="prefetch" href="/notebook/assets/js/157.f51afdd1.js"><link rel="prefetch" href="/notebook/assets/js/158.247f3f23.js"><link rel="prefetch" href="/notebook/assets/js/159.2342ec68.js"><link rel="prefetch" href="/notebook/assets/js/16.bc052b7f.js"><link rel="prefetch" href="/notebook/assets/js/160.98e33fe9.js"><link rel="prefetch" href="/notebook/assets/js/161.b8389795.js"><link rel="prefetch" href="/notebook/assets/js/162.5809ad21.js"><link rel="prefetch" href="/notebook/assets/js/163.6d40855f.js"><link rel="prefetch" href="/notebook/assets/js/164.cd5e8c28.js"><link rel="prefetch" href="/notebook/assets/js/165.c409d97c.js"><link rel="prefetch" href="/notebook/assets/js/166.75cd78fe.js"><link rel="prefetch" href="/notebook/assets/js/167.37552374.js"><link rel="prefetch" href="/notebook/assets/js/168.d4ab1d56.js"><link rel="prefetch" href="/notebook/assets/js/169.39f3c518.js"><link rel="prefetch" href="/notebook/assets/js/17.2a8873d5.js"><link rel="prefetch" href="/notebook/assets/js/170.7993242d.js"><link rel="prefetch" href="/notebook/assets/js/171.09f40b60.js"><link rel="prefetch" href="/notebook/assets/js/172.79168981.js"><link rel="prefetch" href="/notebook/assets/js/173.a75cd141.js"><link rel="prefetch" href="/notebook/assets/js/174.bd510afd.js"><link rel="prefetch" href="/notebook/assets/js/175.c3f8ba94.js"><link rel="prefetch" href="/notebook/assets/js/176.dd9cbd79.js"><link rel="prefetch" href="/notebook/assets/js/177.f53090f5.js"><link rel="prefetch" href="/notebook/assets/js/178.bcda53b0.js"><link rel="prefetch" href="/notebook/assets/js/179.2d510aa5.js"><link rel="prefetch" href="/notebook/assets/js/18.2d0a0d6d.js"><link rel="prefetch" href="/notebook/assets/js/180.6928e4f9.js"><link rel="prefetch" href="/notebook/assets/js/181.6cc94652.js"><link rel="prefetch" href="/notebook/assets/js/182.c7d6fde2.js"><link rel="prefetch" href="/notebook/assets/js/183.1a7eaa90.js"><link rel="prefetch" href="/notebook/assets/js/184.5d52b650.js"><link rel="prefetch" href="/notebook/assets/js/185.2f8eddcd.js"><link rel="prefetch" href="/notebook/assets/js/186.2615bcf2.js"><link rel="prefetch" href="/notebook/assets/js/187.ffb3009d.js"><link rel="prefetch" href="/notebook/assets/js/188.deef127e.js"><link rel="prefetch" href="/notebook/assets/js/189.51b1958b.js"><link rel="prefetch" href="/notebook/assets/js/19.482e846f.js"><link rel="prefetch" href="/notebook/assets/js/190.a5e85724.js"><link rel="prefetch" href="/notebook/assets/js/191.fd2dfc70.js"><link rel="prefetch" href="/notebook/assets/js/192.5cb3b141.js"><link rel="prefetch" href="/notebook/assets/js/193.3a6173b0.js"><link rel="prefetch" href="/notebook/assets/js/194.2b937e4b.js"><link rel="prefetch" href="/notebook/assets/js/195.71b1b3e2.js"><link rel="prefetch" href="/notebook/assets/js/196.d8d64ba1.js"><link rel="prefetch" href="/notebook/assets/js/197.fbea3131.js"><link rel="prefetch" href="/notebook/assets/js/198.25e90057.js"><link rel="prefetch" href="/notebook/assets/js/199.5bef52d0.js"><link rel="prefetch" href="/notebook/assets/js/20.3869e9c1.js"><link rel="prefetch" href="/notebook/assets/js/200.839b8484.js"><link rel="prefetch" href="/notebook/assets/js/201.dcc87a43.js"><link rel="prefetch" href="/notebook/assets/js/202.83abe52e.js"><link rel="prefetch" href="/notebook/assets/js/203.c8c886fe.js"><link rel="prefetch" href="/notebook/assets/js/204.7d91a0aa.js"><link rel="prefetch" href="/notebook/assets/js/205.dd934d84.js"><link rel="prefetch" href="/notebook/assets/js/206.ae9d7602.js"><link rel="prefetch" href="/notebook/assets/js/207.f5ac5260.js"><link rel="prefetch" href="/notebook/assets/js/208.203ba066.js"><link rel="prefetch" href="/notebook/assets/js/209.202991be.js"><link rel="prefetch" href="/notebook/assets/js/21.95b2d828.js"><link rel="prefetch" href="/notebook/assets/js/210.3e7c6db0.js"><link rel="prefetch" href="/notebook/assets/js/211.d231f4d5.js"><link rel="prefetch" href="/notebook/assets/js/212.74210f2c.js"><link rel="prefetch" href="/notebook/assets/js/213.ca497e10.js"><link rel="prefetch" href="/notebook/assets/js/214.256f2f8d.js"><link rel="prefetch" href="/notebook/assets/js/215.e5a91195.js"><link rel="prefetch" href="/notebook/assets/js/22.bfedf3cf.js"><link rel="prefetch" href="/notebook/assets/js/23.07416482.js"><link rel="prefetch" href="/notebook/assets/js/24.54aaf5dd.js"><link rel="prefetch" href="/notebook/assets/js/25.5fddfc47.js"><link rel="prefetch" href="/notebook/assets/js/26.3beace9a.js"><link rel="prefetch" href="/notebook/assets/js/27.8166fc8b.js"><link rel="prefetch" href="/notebook/assets/js/28.45eec4fe.js"><link rel="prefetch" href="/notebook/assets/js/29.7d2c15a3.js"><link rel="prefetch" href="/notebook/assets/js/3.58b1a014.js"><link rel="prefetch" href="/notebook/assets/js/30.a7841312.js"><link rel="prefetch" href="/notebook/assets/js/31.dc9675e8.js"><link rel="prefetch" href="/notebook/assets/js/32.93c6c35d.js"><link rel="prefetch" href="/notebook/assets/js/33.9a64b2f6.js"><link rel="prefetch" href="/notebook/assets/js/34.0c220f3c.js"><link rel="prefetch" href="/notebook/assets/js/35.9f407421.js"><link rel="prefetch" href="/notebook/assets/js/36.ee8ac781.js"><link rel="prefetch" href="/notebook/assets/js/37.569079d1.js"><link rel="prefetch" href="/notebook/assets/js/38.56b32d83.js"><link rel="prefetch" href="/notebook/assets/js/39.6ea9c955.js"><link rel="prefetch" href="/notebook/assets/js/4.5042ba18.js"><link rel="prefetch" href="/notebook/assets/js/40.5bdebc85.js"><link rel="prefetch" href="/notebook/assets/js/41.8607bd5a.js"><link rel="prefetch" href="/notebook/assets/js/42.2063b1d0.js"><link rel="prefetch" href="/notebook/assets/js/43.ff59782c.js"><link rel="prefetch" href="/notebook/assets/js/44.c40eaded.js"><link rel="prefetch" href="/notebook/assets/js/45.bc61bb49.js"><link rel="prefetch" href="/notebook/assets/js/46.e9ea5687.js"><link rel="prefetch" href="/notebook/assets/js/47.a9626a0e.js"><link rel="prefetch" href="/notebook/assets/js/48.9bf986fe.js"><link rel="prefetch" href="/notebook/assets/js/49.dd90158a.js"><link rel="prefetch" href="/notebook/assets/js/5.b9679d2a.js"><link rel="prefetch" href="/notebook/assets/js/50.a9546c5a.js"><link rel="prefetch" href="/notebook/assets/js/51.dcc646ec.js"><link rel="prefetch" href="/notebook/assets/js/52.111a35ff.js"><link rel="prefetch" href="/notebook/assets/js/53.19719081.js"><link rel="prefetch" href="/notebook/assets/js/54.543f990e.js"><link rel="prefetch" href="/notebook/assets/js/55.02863756.js"><link rel="prefetch" href="/notebook/assets/js/56.262a1288.js"><link rel="prefetch" href="/notebook/assets/js/57.a80801ee.js"><link rel="prefetch" href="/notebook/assets/js/58.38d623bc.js"><link rel="prefetch" href="/notebook/assets/js/59.07a6b6b6.js"><link rel="prefetch" href="/notebook/assets/js/6.77dfe150.js"><link rel="prefetch" href="/notebook/assets/js/60.df11d23d.js"><link rel="prefetch" href="/notebook/assets/js/61.764a5b2e.js"><link rel="prefetch" href="/notebook/assets/js/62.28916805.js"><link rel="prefetch" href="/notebook/assets/js/63.f54fb2ba.js"><link rel="prefetch" href="/notebook/assets/js/64.73bb9e27.js"><link rel="prefetch" href="/notebook/assets/js/65.8e45d2c8.js"><link rel="prefetch" href="/notebook/assets/js/66.6cabc639.js"><link rel="prefetch" href="/notebook/assets/js/67.61f4e99c.js"><link rel="prefetch" href="/notebook/assets/js/68.fec9c74e.js"><link rel="prefetch" href="/notebook/assets/js/69.b530b731.js"><link rel="prefetch" href="/notebook/assets/js/7.bac04506.js"><link rel="prefetch" href="/notebook/assets/js/70.e2902def.js"><link rel="prefetch" href="/notebook/assets/js/71.09df6e0a.js"><link rel="prefetch" href="/notebook/assets/js/72.5c611ac8.js"><link rel="prefetch" href="/notebook/assets/js/73.66c43b39.js"><link rel="prefetch" href="/notebook/assets/js/74.243e6a2f.js"><link rel="prefetch" href="/notebook/assets/js/75.de524cab.js"><link rel="prefetch" href="/notebook/assets/js/76.750c2fc0.js"><link rel="prefetch" href="/notebook/assets/js/77.fa7ddd5d.js"><link rel="prefetch" href="/notebook/assets/js/78.192816fd.js"><link rel="prefetch" href="/notebook/assets/js/79.a3f3fcd9.js"><link rel="prefetch" href="/notebook/assets/js/8.48754361.js"><link rel="prefetch" href="/notebook/assets/js/80.c3fd6acb.js"><link rel="prefetch" href="/notebook/assets/js/81.7ba4627a.js"><link rel="prefetch" href="/notebook/assets/js/82.e355d704.js"><link rel="prefetch" href="/notebook/assets/js/83.2579aea2.js"><link rel="prefetch" href="/notebook/assets/js/84.1f72cccf.js"><link rel="prefetch" href="/notebook/assets/js/85.7874726d.js"><link rel="prefetch" href="/notebook/assets/js/86.a863f0c3.js"><link rel="prefetch" href="/notebook/assets/js/87.c8c7690e.js"><link rel="prefetch" href="/notebook/assets/js/88.5d7963f9.js"><link rel="prefetch" href="/notebook/assets/js/89.9391f30b.js"><link rel="prefetch" href="/notebook/assets/js/9.c2fb6f2c.js"><link rel="prefetch" href="/notebook/assets/js/90.76bedd2e.js"><link rel="prefetch" href="/notebook/assets/js/91.e345e87a.js"><link rel="prefetch" href="/notebook/assets/js/92.175f428e.js"><link rel="prefetch" href="/notebook/assets/js/93.f45b4417.js"><link rel="prefetch" href="/notebook/assets/js/94.e3f459de.js"><link rel="prefetch" href="/notebook/assets/js/95.1632f845.js"><link rel="prefetch" href="/notebook/assets/js/96.4d0a41d5.js"><link rel="prefetch" href="/notebook/assets/js/97.39bd1831.js"><link rel="prefetch" href="/notebook/assets/js/98.54282751.js"><link rel="prefetch" href="/notebook/assets/js/99.b60593a3.js">
    <link rel="stylesheet" href="/notebook/assets/css/0.styles.cee65b40.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/notebook/" class="home-link router-link-active"><!----> <span class="site-name">我的笔记</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/notebook/guide/" class="nav-link">
  指南
</a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/notebook/guide/" class="nav-link">
  指南
</a></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>GitFlow工作流指南</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/notebook/gitflow/" aria-current="page" class="sidebar-link">为什么需要版本控制</a></li><li><a href="/notebook/gitflow/什么是Git.html" class="sidebar-link">什么是 Git</a></li><li><a href="/notebook/gitflow/安装Git.html" class="sidebar-link">安装 Git</a></li><li><a href="/notebook/gitflow/Git工作流简介.html" class="sidebar-link">Git 工作流简介</a></li><li><a href="/notebook/gitflow/集中式工作流.html" class="sidebar-link">集中式工作流</a></li><li><a href="/notebook/gitflow/功能分支工作流.html" class="sidebar-link">功能分支工作流</a></li><li><a href="/notebook/gitflow/GitFlow 工作流.html" class="sidebar-link">GitFlow 工作流</a></li><li><a href="/notebook/gitflow/Forking 工作流.html" class="active sidebar-link">Forking 工作流</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/notebook/gitflow/Forking 工作流.html#工作方式" class="sidebar-link">工作方式</a></li><li class="sidebar-sub-header"><a href="/notebook/gitflow/Forking 工作流.html#示例" class="sidebar-link">示例</a></li><li class="sidebar-sub-header"><a href="/notebook/gitflow/Forking 工作流.html#总结" class="sidebar-link">总结</a></li></ul></li><li><a href="/notebook/gitflow/Pull Requests.html" class="sidebar-link">Pull Requests</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="forking-工作流"><a href="#forking-工作流" class="header-anchor">#</a> Forking 工作流</h1> <p>Forking 工作流和前面讨论的几种工作流有根本的不同。这种工作流不是使用单个服务端仓库作为『中央』代码基线，而让各个开发者都有一个服务端仓库。这意味着各个代码贡献者有 2 个 Git 仓库而不是 1 个：一个本地私有的，另一个服务端公开的。</p> <p><img src="/notebook/assets/img/git-workflows-forking.ba2bd4a2.png" alt="img"></p> <p>Forking 工作流的一个主要优势是，贡献的代码可以被集成，而不需要所有人都能 push 代码到仅有的中央仓库中。开发者 push 到自己的服务端仓库，而只有项目维护者才能 push 到正式仓库。这样项目维护者可以接受任何开发者的提交，但无需给他正式代码库的写权限。</p> <p>效果就是一个分布式的工作流，能为大型、自发性的团队（包括了不受信的第三方）提供灵活的方式来安全的协作。也让这个工作流成为开源项目的理想工作流。</p> <h2 id="工作方式"><a href="#工作方式" class="header-anchor">#</a> 工作方式</h2> <p>和其它的 Git 工作流一样，Forking 工作流要先有一个公开的正式仓库存储在服务器上。但一个新的开发者想要在项目上工作时，不是直接从正式仓库克隆，而是 fork 正式项目在服务器上创建一个拷贝。</p> <p>这个仓库拷贝作为他个人公开仓库 —— 其它开发者不允许 push 到这个仓库，但可以 pull 到修改（后面我们很快就会看这点很重要）。在创建了自己服务端拷贝之后，和之前的工作流一样，开发者执行 git clone 命令克隆仓库到本地机器上，作为私有的开发环境。</p> <p>要提交本地修改时，push 提交到自己公开仓库中 —— 而不是正式仓库中。然后，给正式仓库发起一个 pull request，让项目维护者知道有更新已经准备好可以集成了。对于贡献的代码，pull request 也可以很方便地作为一个讨论的地方。</p> <p>为了集成功能到正式代码库，维护者 pull 贡献者的变更到自己的本地仓库中，检查变更以确保不会让项目出错，合并变更到自己本地的 master 分支，然后 push master 分支到服务器的正式仓库中。到此，贡献的提交成为了项目的一部分，其它的开发者应该执行 pull 操作与正式仓库同步自己本地仓库。</p> <h3 id="正式仓库"><a href="#正式仓库" class="header-anchor">#</a> 正式仓库</h3> <p>在 Forking 工作流中，『官方』仓库的叫法只是一个约定，理解这点很重要。从技术上来看，各个开发者仓库和正式仓库在Git看来没有任何区别。事实上，让正式仓库之所以正式的唯一原因是它是项目维护者的公开仓库。</p> <h3 id="forking-工作流的分支使用方式"><a href="#forking-工作流的分支使用方式" class="header-anchor">#</a> Forking 工作流的分支使用方式</h3> <p>所有的个人公开仓库实际上只是为了方便和其它的开发者共享分支。各个开发者应该用分支隔离各个功能，就像在功能分支工作流和 GitFlow 工作流一样。唯一的区别是这些分支被共享了。在 Forking 工作流中这些分支会被 pull 到另一个开发者的本地仓库中，而在功能分支工作流和 GitFlow 工作流中是直接被 push 到正式仓库中。</p> <h2 id="示例"><a href="#示例" class="header-anchor">#</a> 示例</h2> <h3 id="项目维护者初始化正式仓库"><a href="#项目维护者初始化正式仓库" class="header-anchor">#</a> 项目维护者初始化正式仓库</h3> <p><img src="" alt="img"></p> <p>和任何使用 Git 项目一样，第一步是创建在服务器上一个正式仓库，让所有团队成员都可以访问到。通常这个仓库也会作为项目维护者的公开仓库。</p> <p>公开仓库应该是裸仓库，不管是不是正式代码库。所以项目维护者会运行像下面的命令来搭建正式仓库：</p> <div class="language-text extra-class"><pre class="language-text"><code>ssh user@host
git init --bare /path/to/repo.git
</code></pre></div><p>Bitbucket 和 Stash 提供了一个方便的 GUI 客户端以完成上面命令行做的事。这个搭建中央仓库的过程和前面提到的工作流完全一样。如果有现存的代码库，维护者也要 push 到这个仓库中。</p> <h3 id="开发者-fork-正式仓库"><a href="#开发者-fork-正式仓库" class="header-anchor">#</a> 开发者 fork 正式仓库</h3> <p><img src="" alt="img"></p> <p>其它所有的开发需要 fork 正式仓库。可以用 git clone 命令用 SSH 协议连通到服务器，拷贝仓库到服务器另一个位置 —— 是的，fork 操作基本上就只是一个服务端的克隆。Bitbucket 和 Stash 上可以点一下按钮就让开发者完成仓库的 fork 操作。</p> <p>这一步完成后，每个开发都在服务端有一个自己的仓库。和正式仓库一样，这些仓库应该是裸仓库。</p> <h3 id="开发者克隆自己-fork-出来的仓库"><a href="#开发者克隆自己-fork-出来的仓库" class="header-anchor">#</a> 开发者克隆自己 fork 出来的仓库</h3> <p><img src="" alt="img"></p> <p>下一步，各个开发者要克隆自己的公开仓库，用熟悉的 git clone 命令。</p> <p>在这个示例中，假定用 Bitbucket 托管了仓库。记住，如果这样的话各个开发者需要有各自的 Bitbucket 账号，使用下面命令克隆服务端自己的仓库：</p> <div class="language-text extra-class"><pre class="language-text"><code>git clone https://user@bitbucket.org/user/repo.git
</code></pre></div><p>相比前面介绍的工作流只用了一个 origin 远程别名指向中央仓库，Forking 工作流需要 2 个远程别名 —— 一个指向正式仓库，另一个指向开发者自己的服务端仓库。别名的名字可以任意命名，常见的约定是使用 origin 作为远程克隆的仓库的别名（这个别名会在运行 git clone 自动创建），upstream（上游）作为正式仓库的别名。</p> <div class="language-text extra-class"><pre class="language-text"><code>git remote add upstream https://bitbucket.org/maintainer/repo
</code></pre></div><p>需要自己用上面的命令创建 upstream 别名。这样可以简单地保持本地仓库和正式仓库的同步更新。注意，如果上游仓库需要认证（比如不是开源的），你需要提供用户：</p> <div class="language-text extra-class"><pre class="language-text"><code>git remote add upstream https://user@bitbucket.org/maintainer/repo.git
</code></pre></div><p>这时在克隆和 pull 正式仓库时，需要提供用户的密码。</p> <h3 id="开发者开发自己的功能"><a href="#开发者开发自己的功能" class="header-anchor">#</a> 开发者开发自己的功能</h3> <p><img src="" alt="img"></p> <p>在刚克隆的本地仓库中，开发者可以像其它工作流一样的编辑代码、提交修改和新建分支：</p> <div class="language-text extra-class"><pre class="language-text"><code>git checkout -b some-feature
// Edit some code
git commit -a -m &quot;Add first draft of some feature&quot;
</code></pre></div><p>所有的修改都是私有的直到 push 到自己公开仓库中。如果正式项目已经往前走了，可以用 git pull 命令获得新的提交：</p> <div class="language-text extra-class"><pre class="language-text"><code>git pull upstream master
</code></pre></div><p>由于开发者应该都在专门的功能分支上工作，pull 操作结果会都是快进合并。</p> <h3 id="开发者发布自己的功能"><a href="#开发者发布自己的功能" class="header-anchor">#</a> 开发者发布自己的功能</h3> <p><img src="" alt="img"></p> <p>一旦开发者准备好了分享新功能，需要做二件事。首先，通过push他的贡献代码到自己的公开仓库中，让其它的开发者都可以访问到。他的 origin 远程别名应该已经有了，所以要做的就是：</p> <div class="language-text extra-class"><pre class="language-text"><code>git push origin feature-branch
</code></pre></div><p>这里和之前的工作流的差异是，origin 远程别名指向开发者自己的服务端仓库，而不是正式仓库。</p> <p>第二件事，开发者要通知项目维护者，想要合并他的新功能到正式库中。Bitbucket 和 Stash 提供了 Pull Request 按钮，弹出表单让你指定哪个分支要合并到正式仓库。一般你会想集成你的功能分支到上游远程仓库的 master 分支中。</p> <h3 id="项目维护者集成开发者的功能"><a href="#项目维护者集成开发者的功能" class="header-anchor">#</a> 项目维护者集成开发者的功能</h3> <p><img src="" alt="img"></p> <p>当项目维护者收到 pull request，他要做的是决定是否集成它到正式代码库中。有二种方式来做：</p> <ul><li>直接在 pull request 中查看代码</li> <li>pull 代码到他自己的本地仓库，再手动合并</li></ul> <p>第一种做法更简单，维护者可以在 GUI 中查看变更的差异，做评注和执行合并。但如果出现了合并冲突，需要第二种做法来解决。这种情况下，维护者需要从开发者的服务端仓库中 fetch 功能分支，合并到他本地的 master 分支，解决冲突：</p> <div class="language-text extra-class"><pre class="language-text"><code>git fetch https://bitbucket.org/user/repo feature-branch
// 查看变更
git checkout master
git merge FETCH_HEAD
</code></pre></div><p>变更集成到本地的 master 分支后，维护者要 push 变更到服务器上的正式仓库，这样其它的开发者都能访问到：</p> <div class="language-text extra-class"><pre class="language-text"><code>git push origin master
</code></pre></div><p>注意，维护者的 origin 是指向他自己公开仓库的，即是项目的正式代码库。到此，开发者的贡献完全集成到了项目中</p> <h3 id="开发者和正式仓库做同步"><a href="#开发者和正式仓库做同步" class="header-anchor">#</a> 开发者和正式仓库做同步</h3> <p><img src="" alt="img"></p> <p>由于正式代码库往前走了，其它的开发需要和正式仓库做同步：</p> <div class="language-text extra-class"><pre class="language-text"><code>git pull upstream master
</code></pre></div><h2 id="总结"><a href="#总结" class="header-anchor">#</a> 总结</h2> <p>如果你之前是使用 SVN，Forking 工作流可能看起来像是一个激进的范式切换（paradigm shift）。但不要害怕，这个工作流实际上就是在功能分支工作流之上引入另一个抽象层。不是直接通过单个中央仓库来分享分支，而是把贡献代码发布到开发者自己的服务端仓库中。</p> <p>示例中解释了，一个贡献如何从一个开发者流到正式的 master 分支中，但同样的方法可以把贡献集成到任一个仓库中。比如，如果团队的几个人协作实现一个功能，可以在开发之间用相同的方法分享变更，完全不涉及正式仓库。</p> <p>这使得 Forking 工作流对于松散组织的团队来说是个非常强大的工具。任一开发者可以方便地和另一开发者分享变更，任何分支都能有效地合并到正式代码库中。</p></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">2021/4/15 上午11:39:30</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/notebook/gitflow/GitFlow 工作流.html" class="prev">
        GitFlow 工作流
      </a></span> <span class="next"><a href="/notebook/gitflow/Pull Requests.html">
        Pull Requests
      </a>
      →
    </span></p></div> </main></div><div class="global-ui"><!----></div></div>
    <script src="/notebook/assets/js/app.400f01da.js" defer></script><script src="/notebook/assets/js/2.ffba27f2.js" defer></script><script src="/notebook/assets/js/12.125d7a59.js" defer></script>
  </body>
</html>
